package com.yunchao.feature.base.domain.utils

import android.content.Context
import android.util.LruCache
import com.tencent.mmkv.MMKV
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.File

/**
 * 任务缓存类
 */
class FileStorageManager(
    private val context: Context,
    private val ioDispatcher: CoroutineDispatcher = Dispatchers.IO
) {

    companion object {
        private const val FILE_PREFIX = "dispatch_"
        private const val FILE_EXTENSION = ".bin"
        private const val MAX_MEMORY_CACHE_SIZE = 5 * 1024 * 1024 // 5MB
        private const val MMKV_ID = "message_status_mmkv"
    }

    // 内存缓存配置
    private val maxMemory = (Runtime.getRuntime().maxMemory() / 1024).toInt()
    private val cacheSize = maxMemory / 8

    // 内存缓存实现
    private val memoryCache: LruCache<Int, ByteArray> =
        object : LruCache<Int, ByteArray>(cacheSize) {
            override fun sizeOf(key: Int, value: ByteArray): Int {
                return value.size / 1024
            }

            override fun entryRemoved(
                evicted: Boolean,
                key: Int,
                oldValue: ByteArray?,
                newValue: ByteArray?
            ) {
                Timber.d("缓存项被移除: ID=$key, 大小=${oldValue?.size ?: 0} bytes")
            }
        }

    // MMKV 实例
    private val mmkv: MMKV by lazy { MMKV.mmkvWithID(MMKV_ID, MMKV.MULTI_PROCESS_MODE) }

    // 消息状态枚举
    enum class MessageStatus {
        UNREAD,   // 未读
        READ,     // 已读
        DELETED   // 已删除
    }

    /**
     * 保存消息
     * @param data 消息内容
     * @param id 消息ID
     * @param isOffline 是否为离线消息
     * @param status 消息状态，默认为未读
     * @return 是否保存成功
     */
    suspend fun saveMessage(
        data: ByteArray,
        id: Int,
        isOffline: Boolean = false,
        status: MessageStatus = MessageStatus.UNREAD
    ): Boolean = withContext(ioDispatcher) {
        // 先保存状态
        setMessageStatus(id, status)

        // 然后保存消息内容
        val isLargeMessage = data.size > MAX_MEMORY_CACHE_SIZE
        return@withContext when {
            isLargeMessage -> {
                Timber.d("大消息(${data.size} bytes)直接保存到文件")
                saveToFileOnly(data, id)
            }

            isOffline -> {
                Timber.d("小消息(${data.size} bytes)离线保存到文件")
                saveToFileOnly(data, id)
            }

            else -> {
                Timber.d("小消息(${data.size} bytes)在线保存到内存")
                saveToMemoryOnly(id, data)
            }
        }
    }

    /**
     * 只读取消息内容，不更新消息状态
     * @param id 消息ID
     * @return 如果消息不存在则返回null
     */
    suspend fun readMessageWithoutStatusUpdate(id: Int): ByteArray? =
        withContext(ioDispatcher) {
            // 直接从内存或文件读取消息，不涉及状态更新
            return@withContext memoryCache[id] ?: readFromFile(id)
        }

    /**
     * 读取消息并自动更新状态（未读→已读）
     * @param id 消息ID
     * @return 消息内容，如果不存在则返回null
     */
    suspend fun readAndUpdateStatus(id: Int): ByteArray? = withContext(ioDispatcher) {
        // 1. 获取消息内容
        val content = memoryCache[id] ?: readFromFile(id)

        // 2. 如果消息存在且是未读状态，则更新为已读
        return@withContext content?.also {
            if (getMessageStatus(id) == MessageStatus.UNREAD) {
                setMessageStatus(id, MessageStatus.READ)
                Timber.d("消息ID $id 状态已更新为已读")
            }
        }
    }

    /**
     * 删除消息
     * @param id 消息ID
     * @return 是否删除成功
     */
    suspend fun deleteMessage(id: Int): Boolean = withContext(ioDispatcher) {
        // 1. 更新状态为已删除
        setMessageStatus(id, MessageStatus.DELETED)

        // 2. 从内存缓存中移除
        memoryCache.remove(id)

        // 3. 从文件中删除
        deleteFromFile(id)
    }

    /**
     * 设置消息状态
     * @param id 消息ID
     * @param status 要设置的状态
     */
    fun setMessageStatus(id: Int, status: MessageStatus) {
        mmkv.encode("status_$id", status.name)
        Timber.d("设置消息状态: ID=$id, 状态=$status")
    }

    /**
     * 获取消息状态
     * @param id 消息ID
     * @return 消息状态，如果不存在则返回UNREAD
     */
    private fun getMessageStatus(id: Int): MessageStatus {
        return try {
            MessageStatus.valueOf(
                mmkv.decodeString("status_$id", MessageStatus.UNREAD.name)
                    ?: MessageStatus.UNREAD.name
            )
        } catch (e: Exception) {
            Timber.e(e, "获取消息状态失败，返回默认未读状态")
            MessageStatus.UNREAD
        }
    }

    /**
     * 获取所有未读消息ID
     * @return 未读消息ID列表
     */
    fun getAllUnreadMessageIds(): List<Int> {
        return mmkv.allKeys()?.asSequence()
            ?.filter { it.startsWith("status_") }
            ?.mapNotNull { key ->
                val id = key.removePrefix("status_").toIntOrNull()
                if (id != null && getMessageStatus(id) == MessageStatus.UNREAD) id else null
            }
            ?.toList() ?: emptyList()
    }

    /**
     * 获取ID最大的已读消息
     * @return 最大ID的已读消息ID，如果没有则返回null
     */
    fun getMaxReadMessageId(): Int? {
        return mmkv.allKeys()?.asSequence()
            ?.filter { it.startsWith("status_") }
            ?.mapNotNull { key ->
                val id = key.removePrefix("status_").toIntOrNull()
                if (id != null && getMessageStatus(id) == MessageStatus.READ) id else null
            }
            ?.maxOrNull()
    }

    /**
     * 批量更新消息状态
     * @param ids 消息ID列表
     * @param status 要设置的状态
     */
    fun batchUpdateStatus(ids: List<Int>, status: MessageStatus) {
        ids.forEach { id ->
            mmkv.encode("status_$id", status.name)
        }
        Timber.d("批量更新${ids.size}条消息状态为$status")
    }

    /**
     * 清除所有消息状态记录
     */
    fun clearAllStatus() {
        mmkv.allKeys()?.forEach { key ->
            if (key.startsWith("status_")) {
                mmkv.remove(key)
            }
        }
        Timber.d("已清除所有消息状态记录")
    }

    /* ---------------------- 私有方法 ---------------------- */

    /**
     * 仅保存到文件
     */
    private suspend fun saveToFileOnly(data: ByteArray, id: Int): Boolean =
        withContext(ioDispatcher) {
            val filename = generateFileName(id)

            return@withContext try {
                // 先尝试删除旧文件（如果存在）
                deleteFromFile(id)

                // 写入新文件
                context.openFileOutput(filename, Context.MODE_PRIVATE).use { fos ->
                    fos.write(data)
                }

                // 验证文件是否成功写入
                val savedFile = File(context.filesDir, filename)
                if (savedFile.exists() && savedFile.length() == data.size.toLong()) {
                    Timber.d("文件保存成功: ${savedFile.absolutePath}")
                    true
                } else {
                    Timber.e("文件保存后验证失败")
                    false
                }
            } catch (e: Exception) {
                Timber.e(e, "保存文件失败: ${e.message}")
                false
            }
        }

    /**
     * 仅保存到内存
     */
    private fun saveToMemoryOnly(id: Int, data: ByteArray): Boolean {
        return try {
            memoryCache.put(id, data)
            Timber.d("内存保存成功: ID=$id, 大小=${data.size} bytes")
            true
        } catch (e: Exception) {
            Timber.e(e, "内存保存失败")
            false
        }
    }

    /**
     * 从文件读取
     */
    private suspend fun readFromFile(id: Int): ByteArray? = withContext(ioDispatcher) {
        try {
            context.filesDir.listFiles()?.firstOrNull { file ->
                file.name.matches(fileNamePattern(id))
            }?.let {
                context.openFileInput(it.name).use { fis ->
                    fis.readBytes().also {
                        Timber.d("从文件读取成功: ${it.size} bytes")
                    }
                }
            } ?: run {
                Timber.w("未找到ID为${id}的文件")
                null
            }
        } catch (e: Exception) {
            Timber.e(e, "读取文件失败")
            null
        }
    }

    /**
     * 从文件删除
     */
    private suspend fun deleteFromFile(id: Int): Boolean = withContext(ioDispatcher) {
        try {
            val result = context.filesDir.listFiles()?.firstOrNull { file ->
                file.name.matches(fileNamePattern(id))
            }?.delete() == true
            result.also { success ->
                if (success) {
                    Timber.d("文件删除成功")
                } else {
                    Timber.w("文件删除失败或文件不存在")
                }
            }
        } catch (e: Exception) {
            Timber.e(e, "删除文件失败")
            false
        }
    }

    /**
     * 生成带ID的文件名
     */
    private fun generateFileName(id: Int): String {
        return "${FILE_PREFIX}${id}_${System.currentTimeMillis()}${FILE_EXTENSION}"
    }

    /**
     * 文件名匹配模式
     */
    private fun fileNamePattern(id: Int): Regex {
        return Regex("${FILE_PREFIX}${id}(_.+)?${FILE_EXTENSION}")
    }
}